/*
 * @Description:IM通用方法
 * @Author: yangyihui
 * @Date: 2021-04-09 16:36:05
 * @LastEditors: yangyihui
 * @LastEditTime: 2021-11-03 17:01:29
 */
import TIM from 'tim-js-sdk';
import { utilJs } from '../utils/common';
export default {
  created() {
    this._initIM();
  },
  methods: {
    /**
     * @description: IM初始化
     * @param {Object} config  初始化参数
     */
    _initIM() {
      this._isIMLogin = false; //IM是否已经登录
      this._isIMJoinGroup = false; //是否加入群
      this._imCustomMessageStack = []; //自定义消息队列栈（未初始化就进行自定定义消息发送）
      this._isIMReady = false; //SDK是否ready
      this._imRetryCount = 0; //操作次数统计
      if (!this.$tim) {
        this.$tim = TIM.create({
          SDKAppID: 1400318135
        });
      }
      this.$tim.setLogLevel(4);
      // 取消监听
      this.$tim.off(TIM.EVENT.SDK_READY, this._onIMReady);
      this.$tim.off(TIM.EVENT.MESSAGE_RECEIVED, this._onIMMessageReceived);
      this.$tim.off(TIM.EVENT.SDK_NOT_READY, this._onIMNotReady);
      this.$tim.off(TIM.EVENT.KICKED_OUT, this._onIMKickedOut);
      this.$tim.off(TIM.EVENT.ERROR, this._onIMError);

      // 监听事件
      this.$tim.on(TIM.EVENT.SDK_READY, this._onIMReady, this);
      this.$tim.on(TIM.EVENT.MESSAGE_RECEIVED, this._onIMMessageReceived, this);
      this.$tim.on(TIM.EVENT.SDK_NOT_READY, this._onIMNotReady, this);
      this.$tim.on(TIM.EVENT.KICKED_OUT, this._onIMKickedOut, this);
      this.$tim.on(TIM.EVENT.ERROR, this._onIMError, this);
      this.$tim._logoutIM = this._logoutIM;
      Vue.prototype.$tim = this.$tim;
    },
    /**
     * @description:登录IM
     * @param {Object} params  {userID:"必须",userSig:"必须",groupID:"必须",receivedCallBack:"非必须，接受消息回调处理函数名称",errors:{错误上报附加参数 非必须}}
     * @return {*}
     */
    _loginIM: function(params) {
      if (!this.$tim) {
        return;
      }
      this._imConfig = params;
      return this.$tim
        .login({
          userID: params.userID,
          userSig: params.userSig
        })
        .then(imResponse => {
          this._isIMLogin = true;
          this._imRetryCount = 0;
          //重新登录（SDK不会走ready回调！！！）
          if (imResponse.data.repeatLogin === true) {
            this._isIMReady = true;
            this._joinGroup({
              groupID: this._imConfig.groupID
            });
          }
        })
        .catch(imError => {
          if ((imError.code == 'ECONNABORTED' || imError.code == 'ETIMEDOUT') && this._imRetryCount < 3) {
            this._imRetryCount++;
            this._loginIM(params);
          } else {
            this._imRetryCount = 0;
            this.$showCjToast({
              text: '您加入聊天失败，请刷新重试！',
              type: 'warn',
            });
            // this._errorLog({
            //   errorIntro: 'IM登录失败',
            //   errorMsg: imError
            // });
          }
        });
    },
    /**
     * @description: IM-登出（即时通信 IM，通常在切换帐号的时候调用，清除登录态以及内存中的所有数据。）
     */
    _logoutIM() {
      if (!this.$tim || !this._isIMLogin) {
        return;
      }
      this.$tim.off(TIM.EVENT.SDK_READY, this._onIMReady);
      this.$tim.off(TIM.EVENT.MESSAGE_RECEIVED, this._onIMMessageReceived);
      this.$tim.off(TIM.EVENT.SDK_NOT_READY, this._onIMNotReady);
      this.$tim.off(TIM.EVENT.KICKED_OUT, this._onIMKickedOut);
      this.$tim.off(TIM.EVENT.ERROR, this._onIMError);
      this.$tim.logout();
      Vue.prototype.$tim = this.$tim = null;
    },
    /**
     * @description: IM的SDK已经READY
     * @param {Object} event
     */
    _onIMReady(event) {
      this._isIMReady = true;
      this._joinGroup({
        groupID: this._imConfig.groupID
      });
    },
    /**
     * @description: 收到推送的单聊、群聊、群提示、群通知的新消息
     * @param {Object} event
     */
    _onIMMessageReceived: function(event) {
      const messageData = event.data;
      for (let i = 0; i < messageData.length; i++) {
        const message = messageData[i];
        if (message.type === TIM.TYPES.MSG_CUSTOM && message.to == this._imConfig.groupID) {
          let dataContent = JSON.parse(message.payload.data);
          if (this._imConfig.receivedCallBack) {
            //如果回调处理方法需要自定的情况(默认用_handlerIMMessage)
            this._imConfig.receivedCallBack.call(this, dataContent);
          } else {
            this._handlerIMMessage(dataContent);
          }
        }
      }
    },
    /**
     * @description:收到 SDK 进入 not ready 状态通知，此时 SDK 无法正常工作
     */
    _onIMNotReady: function() {
      this._isIMReady = false;
    },
    /**
     * @description:被剔除
     */
    _onIMKickedOut(event) {
    },
    /**
     * @description:登录失败的相关信息
     */
    _onIMError() {
      //心跳检测失败也会报错，故不上报
    },
    /**
     * @description:加群(群是由后端建立，前端不参与建群)
     * @param {Object} params
     */
    _joinGroup: function(params) {
      return new Promise((resolve, reject) => {
        if (!this.$tim) {
          reject();
        }
        const promise = this.$tim.joinGroup({
          groupID: params.groupID + '',
          type: TIM.TYPES.GRP_AVCHATROOM //（直播群）类型的群组
        });
        promise
          .then(imResponse => {
            switch (imResponse.data.status) {
              case TIM.TYPES.JOIN_STATUS_WAIT_APPROVAL: // 等待管理员同意
                break;
              case TIM.TYPES.JOIN_STATUS_SUCCESS: // 加群成功
              case TIM.TYPES.JOIN_STATUS_ALREADY_IN_GROUP: // 已经在群中
                this._isIMJoinGroup = true;
                this._imRetryCount = 0;
                if (this._imCustomMessageStack.length) {
                  //存在队列，执行
                  this._imCustomMessageStack.forEach((item, index) => {
                    this._createCustomMessage(item.data, item.userID, item.successCB, item.errorCB);
                    if (index == this._imCustomMessageStack.length - 1) {
                      this._imCustomMessageStack = [];
                    }
                  });
                }
                resolve();
                break;
              default:
                break;
            }
          })
          .catch(imError => {
            //加群失败 imError.code == 60008 &&
            if (this._imRetryCount < 3) {
              //对于请求超时的用户，重新执行加群操作,递归3次依然不行直接抛错误
              this._imRetryCount++;
              this._joinGroup(params);
            } else {
              this._imRetryCount = 0;
              console.error('IM加群失败joinGroup error', imError); // 申请加群失败的相关信息
              // this._errorLog({
              //   errorIntro: 'IM加群失败',
              //   errorMsg: imError
              // });
              reject();
            }
          });
      });
    },
    /**
     * @description:IM退群（群是由后端建立了）
     */
    _quitGroup(params) {
      if (!this.$tim) {
        return;
      }
      const promise = this.$tim.quitGroup(params.groupID + '');
      promise
        .then(imResponse => {
          console.log('退群成功_quitGroup success', imResponse);
        })
        .catch(imError => {
          this._errorLog({
            errorIntro: 'IM退群失败',
            errorMsg: imError
          });
          console.warn('退群失败 quitGroup error', imError);
        });
      return promise;
    },
    /**
     * @description:发送消息 暴露给外部使用
     * @param {Object} data  发送数据
     * @param {String} userID  用户id（非必须，如果发给指定的人则需要传递）
     */
    _sendCustomMessage(data, userID) {
      if (!this._isIMJoinGroup) {
        //未加群成功，入队列(每个sendCustomMessage都是一个promise)
        return new Promise((resolve, reject) => {
          this._imCustomMessageStack.push({
            data: data,
            userID: userID,
            successCB: resolve,
            errorCB: reject
          });
        });
      } else {
        //加群成功
        return new Promise((resolve, reject) => {
          this._createCustomMessage(data, userID, resolve, reject);
        });
      }
    },
    /**
     * @description:
     * @param {Object} data  发送数据
     * @param {String} userID  用户id（非必须，入职发给指定的人则需要传递）
     */
    _createCustomMessage(data, userID, resolve, reject) {
      let prevPath = this.$route.path;
      let message = this.$tim.createCustomMessage({
        to: userID || this._imConfig.groupID + '',
        conversationType: TIM.TYPES.CONV_GROUP,
        priority: this._imConfig.userRole > 1 ? TIM.TYPES.MSG_PRIORITY_HIGH : TIM.TYPES.MSG_PRIORITY_NORMAL,
        payload: {
          data: JSON.stringify(data),
          description: '',
          extension: ''
        }
      });
      let promise = this.$tim.sendMessage(message);
      promise
        .then(function(res) {
          console.log('自定义发消息成功！', data);
          resolve();
        })
        .catch(res => {
          //错误收集，上报日志
          console.error('自定义发消息失败！', res, data);
          if (res.code == 2100 || res.code == 2999) {
            this._isIMJoinGroup = false;
            console.log('还未加群');
            this._joinGroup({
              groupID: this._imConfig.groupID
            })
              .then(() => {
                console.log('重新加群成功');
                this._createCustomMessage(data, userID, resolve, reject);
              })
              .catch(() => {
                this.$showCjToast({
                  text: '网络开小差了，请刷新重试！',
                  type: 'warn',
                });
                this._errorLog({
                  errorIntro: 'IM自定义消息发送失败',
                  errorMsg: res,
                  sendData: data
                });
              });
          } else {
            if (prevPath == this.$route.path) {
              this.$showCjToast({
                text: '网络开小差了，请刷新重试！',
                type: 'warn',
              });
              this._errorLog({
                errorIntro: 'IM自定义消息发送失败',
                errorMsg: res,
                sendData: data
              });
            }
          }
        });
    },
    //去掉绑定
    _offMessageReceive: function() {
      this.$tim.off(TIM.EVENT.MESSAGE_RECEIVED, this._onIMMessageReceived, this);
    },
    //错误上报
    _errorLog(params) {
      utilJs.reprotError({
        errorFrom: 'liveError',
        errorType: 'IM',
        curTime: new Date().toLocaleString(),
        imConfig: this._imConfig,
        errorIntro: params.errorIntro || '',
        errorMsg: params.errorMsg || '',
        code: params.code || '',
        sendData: params.data || '' //发送的数据
      });
    },
    _sendCustomMsgByServer(msgItem) {
      return new Promise(resolve => {
        utilJs.postMethod(`${global.apiurl}social/sendCustMsgToJiGuang/${msgItem.roomId}`, { msg_body: msgItem }, () => {
          resolve();
        });
      });
    }
  }
};
